import { ref, computed } from 'vue';
import { cloneDeep } from 'lodash-es';
import type { State } from '../types';

// value.get, value.set
declare class Value<T = any> {
  get value(): WithTableSign<T>[];
  set value(value: T[]);
}

export type TableSign = {
  __id__: string;
  __state__: State;
};

export type WithTableSign<T> = T & TableSign;

export type WithoutTableSign<WithTableSigna> = Omit<
  WithTableSigna,
  keyof TableSign
>;

export type DataSource<T> = Value<T> & {
  copy(indexOrId: number | string): void;
  remove(indexOrId: number | string): void;
  insert(raw: T, index?: number): void;
};

// 格式化table-data
function toTableData<T>(data: T[]) {
  return data.map((item) => withTableSign(item));
}

// 给对象添加 __id__, __state__
function withTableSign<T>(
  raw: T,
  state: State = 'edit'
): WithTableSign<T> {
  const clone = cloneDeep(raw);

  return Object.assign(clone, {
    __id__: crypto.randomUUID(),
    __state__: state || 'edit',
  });
}

export function useDataSource<T = any>(
  initData?: T[]
): DataSource<T> {
  initData = initData ? toTableData(initData) : [];
  const dataSource = ref<WithTableSign<T>[]>(initData as any);

  const computedData = computed<any>({
    get() {
      return dataSource.value as any as WithTableSign<T>;
    },
    set(newValue) {
      const tableData = toTableData(newValue);
      dataSource.value = tableData as any;
    },
  });

  // 根据index插入数组，index没有则从尾部插入
  function insert(raw: T, index?: number) {
    const data = withTableSign(raw) as any;
    if (index) {
      dataSource.value.splice(index, 0, data);
    } else {
      dataSource.value.push(data);
    }
  }

  function copy(indexOrId: number | string) {
    if (typeof indexOrId === 'number') {
      copyByIndex(indexOrId);
    } else {
      copyById(indexOrId);
    }
  }

  // 根据index复制数组元素
  function copyByIndex(index: number) {
    const max = dataSource.value.length - 1;
    if (max === 0 || index > max || index < 0) return;

    const item = dataSource.value[index];
    if (!item) return;

    const copy = withTableSign(item);
    dataSource.value.splice(index + 1, 0, copy);
  }

  function copyById(id: string) {
    const index = dataSource.value.findIndex((e) => e.__id__ === id);
    if (index > -1) {
      copyByIndex(index);
    }
  }

  /**
   * 根据id或者数组索引删除一行
   */
  function remove(indexOrId: number | string) {
    if (typeof indexOrId === 'number') {
      removeByIndex(indexOrId);
    } else {
      removeById(indexOrId);
    }
  }

  function removeByIndex(index: number) {
    dataSource.value = dataSource.value.filter(
      (_, idx) => idx !== index
    );
  }

  function removeById(id: string) {
    dataSource.value = dataSource.value.filter(
      (item) => item.__id__ !== id
    );
  }

  const methods: any = {
    insert,
    copy,
    remove,
  };

  return Object.assign(computedData, methods);
}
